package main

import (
	"fmt"
	"reflect"
)

// 接口类型嵌入
type goods interface {
	getGoodsList()
	getGoodsInfo()
}
type user interface {
	getUserList()
	getUserInfo()
}
type order interface {
	goods
	user
	getOrderInfo()
}
type userDetail interface {
	getUserList()
}
type orderDetail interface {
	user
	userDetail // Go 1.14 版本之前会报错: Error: duplicate method getUserList, Go 1.14 版本之后不会报错
}

// 结构体类型嵌入
type myInt int
type userSt struct {
	id   string
	name string
	age  int
}
type orderSt struct {
	id string
}
type userIn interface {
	getUserInfo()
}
type result struct {
	myInt   //自定义类型
	userSt  //结构体类型
	orderSt //结构体类型
	userIn  //接口类型
	code    int
	message string
}

// 带有嵌入类型的新类型“继承”了哪些方法?
type T1 struct{}

func (T1) T1M1()   { println("T1's M1") }
func (*T1) PT1M2() { println("PT1's M2") }

type T2 struct{}

func (T2) T2M1()   { println("T2's M1") }
func (*T2) PT2M2() { println("PT2's M2") }

type T struct {
	T1
	*T2
}

// 基于接口类型创建的 defined 类型
type yourInt int
type yourInterface interface {
	M1()
	M2()
}
type newInt yourInt             // 基于已存在的类型 yourInt 创建新的defined类型 newInt
type newInterface yourInterface // 基于已存在的接口类型 yourInterface 创建新defined接口类型 newInterface

// 基于结构体类型创建的 defined 类型
type myT1 T1

// 基于结构体类型创建的 alias 类型
type myT2 = T1

func main() {
	res := result{
		userSt: userSt{
			id:   "1001",
			name: "zhangsan",
			age:  18,
		},
		orderSt: orderSt{
			id: "123456",
		},
		code:    200,
		message: "OK",
	}
	fmt.Println(res) //{0 {zhangsan 18} <nil> 200 OK}

	fmt.Println(res.userSt.name) //zhangsan
	fmt.Println(res.name)        //zhangsan
	// fmt.Println(res.id)          //报错:  ambiguous selector res.id,需要改为下面的方式
	fmt.Println(res.userSt.id)  //1001
	fmt.Println(res.orderSt.id) //123456
	println()

	//类型 T 的方法集合 = T1 的方法集合 + *T2 的方法集合
	//类型 *T 的方法集合 = *T1 的方法集合 + *T2 的方法集合
	t := T{
		T1: T1{},
		T2: &T2{},
	}
	dumpMethodSet(t)  //main.T 的方法集合: PT2M2, T1M1, T2M1,
	dumpMethodSet(&t) //*main.T 的方法集合: PT1M2, PT2M2, T1M1, T2M1,
	println()

	// defined : myT1 与 T1 是两个不同的类型，新类型 myT1 并没有“继承” 原 defined 类型 T1 的任何一个方法，新 defined 类型要想实现那些接口，仍然需要重新实现接口的所有方法。
	var t1 T1
	var pt1 *T1
	var t2 myT1
	var pt2 *myT1
	dumpMethodSet(t1)  //main.T1 的方法集合: T1M1,
	dumpMethodSet(pt1) //*main.T1 的方法集合: PT1M2, T1M1,
	dumpMethodSet(t2)  //main.myT1 的方法集合为空
	dumpMethodSet(pt2) //*main.myT1 的方法集合为空
	println()

	// alias : 无论原类型是接口类型还是非接口类型，类型别名都与原类型拥有完全相同的方法集合。
	var q1 T1
	var pq1 *T1
	var q2 myT2
	var pq2 *myT2
	dumpMethodSet(q1)  //main.T1 的方法集合: T1M1,
	dumpMethodSet(pq1) //*main.T1 的方法集合: PT1M2, T1M1,
	dumpMethodSet(q2)  //main.T1 的方法集合: T1M1,
	dumpMethodSet(pq2) //*main.T1 的方法集合: PT1M2, T1M1,
	println()
}

// 输出方法集合
func dumpMethodSet(i interface{}) {
	dynamicType := reflect.TypeOf(i)
	if dynamicType == nil {
		fmt.Printf("没有动态类型 \n")
		return
	}

	n := dynamicType.NumMethod()
	if n == 0 {
		fmt.Printf("%s 的方法集合为空\n", dynamicType)
		return
	}
	fmt.Printf("%s 的方法集合: ", dynamicType)
	for j := 0; j < n; j++ {
		fmt.Print(dynamicType.Method(j).Name, ", ")
	}
	fmt.Printf("\n")
}
